Skip to content

feat(cli): add token subcommand for Graph API bearer token export#12

Open
stevenobiajulu wants to merge 2 commits intomainfrom
feat/token-subcommand
Open

feat(cli): add token subcommand for Graph API bearer token export#12
stevenobiajulu wants to merge 2 commits intomainfrom
feat/token-subcommand

Conversation

@stevenobiajulu
Copy link
Copy Markdown
Member

@stevenobiajulu stevenobiajulu commented Apr 4, 2026

Summary

Add a token subcommand that prints a Microsoft Graph API bearer token to stdout for use in sandboxed environments where the OS keychain is unavailable.

  • Auto-selects mailbox when exactly one is configured
  • Requires --mailbox if multiple exist (exit 2 with list)
  • Strictly noninteractive — expired auth directs to configure
  • Awaits stdout flush to prevent truncation on pipe

Usage

# One mailbox — auto-selects
export GRAPH_TOKEN=$(npx email-agent-mcp token)

# Multiple mailboxes
export GRAPH_TOKEN=$(npx email-agent-mcp token --mailbox [email protected])

# One-shot (most secure — token only lives for the command)
GRAPH_TOKEN=$(npx email-agent-mcp token) openshell sandbox create --name test --from openclaw

Motivation

NemoClaw sandboxes pass credentials as env vars at creation time (same pattern as Discord/Slack bot tokens). This command enables gh auth token-style piping for Graph API tokens. See #15 for the NemoClaw sandbox blocker that motivated this.

Test plan

Unit tests (6 new, all pass)

  • No mailboxes configured → exit 1, stderr: "no mailboxes configured"
  • --mailbox nonexistent → exit 2, stderr: "not found"
  • Multiple mailboxes without --mailbox → exit 2, stderr lists available mailboxes
  • Single mailbox with expired/missing credentials → exit 1 (auth error)
  • parseCliArgs(['token']) → command is 'token'
  • parseCliArgs(['token', '--mailbox', 'x']) → mailbox is 'x'

Manual end-to-end tests (performed against live Graph API)

  • token prints valid JWT to stdout (2610 chars, starts with eyJ0eXAi)
  • Token works against Graph API — curl /v1.0/me returns "Steven Obiajulu"
  • --mailbox [email protected] returns valid token
  • Token used inside NemoClaw sandbox to successfully GET emails and reproduce PATCH 403
  • All 95 existing tests pass (no regressions)

Not tested (would need additional infra)

  • stdout flush under backpressure (tested implicitly via $(...) capture)
  • Multiple real mailboxes (only one configured in test environment)

Print a Microsoft Graph API bearer token to stdout for use in sandboxed
environments (e.g., NemoClaw) where the macOS Keychain is unavailable.

Follows `gh auth token` convention: token to stdout, errors to stderr.

Auto-selects when one mailbox is configured; requires --mailbox if
multiple exist (exit 2 with list). Strictly noninteractive — expired
auth directs user to `configure` instead of starting device code flow.

Includes stdout flush await to prevent truncation when CLI wrapper
calls process.exit() after runCli() resolves.
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 4, 2026

Codecov Report

❌ Patch coverage is 82.35294% with 6 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
packages/email-mcp/src/cli.ts 82.35% 5 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

Tests cover:
- No mailboxes configured → exit 1 with guidance
- Unknown --mailbox → exit 2 with "not found"
- Multiple mailboxes without --mailbox → exit 2 with list
- Expired/missing credentials → exit 1 (auth error)
- Arg parsing for token and token --mailbox
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant